package com.cictec.middleware.commons.utils.elasticsearch;

import java.net.UnknownHostException;
import java.util.List;
import java.util.regex.Pattern;

import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsRequest;
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.FieldSortBuilder;

import com.cictec.middleware.commons.utils.PropertiesUtils;

/**
 * ES工具类
 * @author qilei
 *
 */
public class ESUtils {

	static Pattern badChars = Pattern.compile("\\s*[\\s~!\\^&\\(\\)\\-\\+:\\|\\\\\"\\\\$]+\\s*");

	private static Client clients = getClient();

	private ESUtils() {

	}

	/**
	 * 关闭对应client
	 * @param client
	 */
	public static void close(Client client) {
		try {
			client.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void flush(Client client, String indexName, String indexType) {
		try {
			client.admin().indices().flush(new FlushRequest(indexName.toLowerCase(), indexType)).actionGet();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 根据默认系统默认配置初始化库,如果已经有连接则使用该连接
	 * @return
	 */
	public static Client getClient() {
		if (clients != null) {
			return clients;
		}

		try {
			clients = newClient();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}

		return clients;

	}

	/**
	 * 初始化并连接elasticsearch集群，返回连接后的client
	 * @return 返回连接的集群的client
	 * @throws UnknownHostException 
	 */
	public static Client newClient() throws UnknownHostException {

		String clusterName = PropertiesUtils.getString("elasticsearch.ip", "cictec");
		boolean clientTransportSniff = PropertiesUtils.getBoolean("elasticsearch.clientTransportSniff", true);	// 是否自动发现新加入的节点
		String hostname = PropertiesUtils.getString("elasticsearch.host"); // es服务器的host
		
		
		return newClient(clusterName, clientTransportSniff, hostname);

	}

	/**
	 * 初始化并连接elasticsearch集群，返回连接后的client
	 * @param clusterName 中心节点名称
	 * @param clientTransportSniff 是否自动发现新加入的节点
	 * @param nodeIpInfo 集群节点所在服务器IP，支持多个 ip:port 例如：127.0.0.1:9300,127.0.0.1:9301...
	 * @return 返回连接的集群的client
	 */
	public static Client newClient(String clusterName, boolean clientTransportSniff, String nodeIpInfo) throws UnknownHostException {
		
		EsClientBuilder clientBuilder = new EsClientBuilder();
		clientBuilder.setClusterName(clusterName);
		clientBuilder.setNodeIpInfo(nodeIpInfo);

		return clientBuilder.init();

	}
	

	public static boolean indicesExists(Client client, String indexName) {
		IndicesExistsRequest ier = new IndicesExistsRequest();
		ier.indices(new String[] { indexName.toLowerCase() });
		return client.admin().indices().exists(ier).actionGet().isExists();

	}

	public static boolean typesExists(Client client, String indexName, String indexType) {

		if (indicesExists(client, indexName)) {
			TypesExistsRequest ter = new TypesExistsRequest(new String[] { indexName.toLowerCase() }, indexType);
			return client.admin().indices().typesExists(ter).actionGet().isExists();
		}
		return false;

	}

	/**
	 * 
	 * 根据索引数据id删除索引
	 * 
	 * @param indexName 索引名称
	 * @param indexType 索引类型
	 * @param id  对应数据ID
	 * 
	 */
	public static void deleteIndex(Client client, String indexName, String indexType, String id) {

		try {
			client.prepareDelete(indexName.toLowerCase(), indexType.toLowerCase(), id).execute().actionGet();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * 根据索引名称删除索引
	 * @param indexName 索引名称
	 * 
	 */

	public static void deleteIndex(String indexName) {

		IndicesExistsRequest ier = new IndicesExistsRequest();
		ier.indices(new String[] { indexName.toLowerCase() });
		boolean exists = getClient().admin().indices().exists(ier).actionGet().isExists();
		if (exists) {
			getClient().admin().indices().prepareDelete(indexName.toLowerCase()).execute().actionGet();
		}

	}

	public static SearchHits search(String indexName, String indexType, QueryBuilder boolQuery,
			List<FieldSortBuilder> sortBuilders, int from, int size) throws NoNodeAvailableException {

		if (getClient() == null) {
			return null;
		}

		// 去掉不存在的索引
		IndicesExistsRequest ier = new IndicesExistsRequest();
		ier.indices(new String[] { indexName });
		boolean exists = getClient().admin().indices().exists(ier).actionGet().isExists();
		if (exists) {
			getClient().admin().indices().open(new OpenIndexRequest(indexName)).actionGet();
		} else {
			throw new IndexNotFoundException(indexName);
		}

		try {
			getClient().admin().indices().refresh(new RefreshRequest(indexName)).actionGet();
		} catch (IndexNotFoundException e) {
			e.printStackTrace();
		}

		SearchRequestBuilder searchRequestBuilder = getClient().prepareSearch(indexName);

		searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
		searchRequestBuilder.setFrom(from);
		searchRequestBuilder.setSize(size);
		searchRequestBuilder.setExplain(false);
		searchRequestBuilder.setQuery(boolQuery);
		if (sortBuilders != null && sortBuilders.size() > 0) {

			for (FieldSortBuilder sortBuilder : sortBuilders) {
				searchRequestBuilder.addSort(sortBuilder);
			}
		}

		return searchRequestBuilder.execute().actionGet().getHits();

	}

	public static SearchHits search(String indexName, String indexType, String[] keywords, String[] channelIdArr, int from, int size) throws NoNodeAvailableException, IndexNotFoundException {

		if (getClient() == null) {
			return null;
		}

		// 去掉不存在的索引
		IndicesExistsRequest ier = new IndicesExistsRequest();
		ier.indices(new String[] { indexName });
		boolean exists = getClient().admin().indices().exists(ier).actionGet().isExists();
		if (exists) {
			getClient().admin().indices().open(new OpenIndexRequest(indexName)).actionGet();
		} else {
			throw new IndexNotFoundException(indexName);
		}

		try {
			getClient().admin().indices().refresh(new RefreshRequest(indexName)).actionGet();
		} catch (IndexNotFoundException e) {
			e.printStackTrace();
		}

		SearchRequestBuilder searchRequestBuilder = getClient().prepareSearch(indexName);
		searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
		searchRequestBuilder.setFrom(from);
		searchRequestBuilder.setSize(size);
		searchRequestBuilder.setExplain(true);

		BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

		StringBuffer totalKeys = new StringBuffer();
		for (String keyword : keywords) {
			totalKeys.append(keyword);
		}

		if (!totalKeys.toString().equals("*")) {

			for (String keyword : keywords) {
				if (keyword == null || keyword.trim().length() == 0) {
					continue;
				}

				keyword = badChars.matcher(keyword).replaceAll("");
				if (keyword == null || keyword.trim().length() == 0) {
					continue;
				}

				if (keyword.indexOf("*") != -1 || keyword.indexOf("×") != -1 || keyword.indexOf("?") != -1 || keyword.indexOf("？") != -1) {

					keyword = keyword.replaceAll("×", "*").replaceAll("？", "?");
					BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();
					String indexColumnNames[] = new String[0];
					for (String indexColumnName : indexColumnNames) {
						subBoolQuery.should(QueryBuilders.wildcardQuery(indexColumnName.toLowerCase(), keyword));
					}
					boolQuery.must(subBoolQuery);
				} else {
					QueryStringQueryBuilder qb = QueryBuilders.queryStringQuery("\"" + keyword + "\"");
					boolQuery.must(qb);
				}
			}

		} else {
			// boolQuery.should(QueryBuilders.queryString("*"));
		}

		if (channelIdArr != null && channelIdArr.length > 0) {
			TermQueryBuilder inQuery = QueryBuilders.termQuery("channelid_", channelIdArr);
			boolQuery.must(inQuery);
		}

		searchRequestBuilder.setQuery(boolQuery);
		return searchRequestBuilder.execute().actionGet().getHits();

	}

	public static String preReadString(String read, int maxLength) {

		if (read == null || read.trim().length() == 0) {
			return "";
		}

		read = read.trim();
		if (read.length() <= maxLength) {
			return read;
		}

		/* 
		if (keywords != null && keywords.length > 0) {
			for (String keyword : keywords) {
				if (keyword == null || keyword.trim().length() == 0) {
					continue;
				}
				keyword = badChars.matcher(keyword).replaceAll("");
				int loc = read.indexOf(keyword);
				if (loc != -1) {
					if (loc <= maxLength) {
						return read.substring(0, maxLength);
					} else {
						int aft = read.length() - loc;
						if (aft > (maxLength / 2)) {
							return read.substring(loc - maxLength / 2, loc + maxLength / 2 + 1);
						} else {
							return read.substring(loc - maxLength + aft, loc + aft);
						}
					}
				}
			}
		}
		*/

		return read.substring(0, maxLength);

	}

}